package repository

import (
	"errors"
	"gluenet/internal/glue-srvp/adapter/repository/mysql"
	"gluenet/internal/glue-srvp/domain/dependency"
	"gluenet/internal/glue-srvp/domain/entity"
	"gluenet/internal/pkg/infra"
	"gluenet/internal/pkg/infra/prepare"
)

func init() {
	prepare.RegisterRepo(func() {
		repo := NewInstanceMetaRepo()
		prepare.InjectDependency(func() dependency.InstanceMetaRepo {
			return repo
		})
	})
}

func NewInstanceMetaRepo() *InstanceMetaRepo {
	r := &InstanceMetaRepo{}
	return r
}

// Meta 是对domain/dependency的MetaRepo的一个实现，具体函数功能请参见接口定义
type InstanceMetaRepo struct {
	Meta
}

func (c InstanceMetaRepo) AddInstance(obj *entity.Instance, auth infra.AuthInfo) error {
	var (
		err error
	)

	session := mysql.DB.NewSession()
	defer session.Close()

	if err = session.Begin(); err != nil {
		return err
	}

	if _, err = session.InsertOne(obj); err != nil {
		session.Rollback()
		return err
	}

	obj.InstanceToUser.UserId = auth.UserId
	obj.InstanceToUser.ConfigId = obj.Id
	obj.InstanceToUser.GroupId = auth.GroupId
	if _, err = session.InsertOne(obj.InstanceToUser); err != nil {
		session.Rollback()
		return err
	}

	if err = session.Commit(); err != nil {
		session.Rollback()
		return err
	}
	return nil
}

func (c InstanceMetaRepo) DelInstance(obj *entity.Instance, auth infra.AuthInfo) error {
	var (
		err error
	)

	obj.InstanceToUser.ConfigId = obj.Id
	switch auth.AuthLevel {
	case 0:
	case 1:
		obj.InstanceToUser.GroupId = auth.GroupId
	case 2:
		obj.InstanceToUser.UserId = auth.UserId
		obj.InstanceToUser.GroupId = auth.GroupId
	}

	session := mysql.DB.NewSession()
	defer session.Close()

	if err = session.Begin(); err != nil {
		return err
	}

	affect, err := session.Delete(obj.InstanceToUser)
	if err != nil {
		session.Rollback()
		return err
	}
	if affect == 0 {
		return errors.New("affect row: 0")
	}
	if _, err = session.ID(obj.Id).Delete(obj); err != nil {
		session.Rollback()
		return err
	}

	if err = session.Commit(); err != nil {
		session.Rollback()
		return err
	}

	return nil
}

func (c InstanceMetaRepo) UptInstance(obj *entity.Instance, auth infra.AuthInfo) error {
	var (
		ok     bool
		affect int64
		err    error
	)

	obj.InstanceToUser.ConfigId = obj.Id
	switch auth.AuthLevel {
	case 0:
	case 1:
		obj.InstanceToUser.GroupId = auth.GroupId
	case 2:
		obj.InstanceToUser.UserId = auth.UserId
		obj.InstanceToUser.GroupId = auth.GroupId
	}

	session := mysql.DB.NewSession()
	defer session.Close()

	if err = session.Begin(); err != nil {
		return err
	}

	if ok, err = session.Get(&obj.InstanceToUser); err != nil {
		session.Rollback()
		return err
	}
	if !ok {
		session.Rollback()
		return infra.AuthFailed
	}

	if affect, err = session.ID(obj.Id).Update(obj); !ok {
		session.Rollback()
		return err
	}

	if err = session.Commit(); err != nil {
		session.Rollback()
		return err
	}

	if affect == 0 {
		return errors.New("affect row: 0")
	}

	return nil
}

func (c InstanceMetaRepo) FindInstance(objs *[]entity.Instance, auth infra.AuthInfo, query interface{}, args ...interface{}) error {
	var (
		join        = "INNER"
		table       = "srvp_instance"
		tableToUser = "srvp_instance_to_user"
		condition   = "srvp_instance.id=srvp_instance_to_user.instance_id"
	)

	switch auth.AuthLevel {
	case 2:
		return mysql.DB.Select(table+".*").Join(join, tableToUser, condition).
			Where("user_id=? and group_id=?", auth.UserId, auth.GroupId).Where(query, args).Find(objs)
	case 1:
		return mysql.DB.Select(table+".*").Join(join, tableToUser, condition).
			Where("group_id=?", auth.GroupId).Where(query, args).Find(objs)
	case 0:
		return mysql.DB.Where(query, args).Find(objs)
	default:
		return nil
	}
}
